package cn.android666.recorddemowithnoise

import java.io.*

class WavWriter(
    @Suppress("MemberVisibilityCanBePrivate")
    val wavFile: File,
    /** 采样率 */
    private val sampleRate: Int,
    /** 位深 */
    private val bitDepth: Int,
    /** 通道数量  */
    private val channelCount: Int,
    ) {

    private val raf = RandomAccessFile(wavFile, "rws")
    private var dataTotalLength = 0

    init {
        writeHeader(0)
    }

    private fun writeHeader(dataTotalLength: Int) {
        val bytesPerFrame = bitDepth / 8 * channelCount
        val bytesPerSec = bytesPerFrame * sampleRate
        writeString("RIFF")         // 资源交换文件标志（RIFF）
        writeInt(36 + dataTotalLength) // 从下个地址开始到文件尾的总字节数(即前8个字节不算)
        writeString("WAVE")     // WAV文件标志（WAVE）
        writeString("fmt ")     // 波形格式标志（fmt ），最后一位空格。
        writeInt(16)          // 过滤字节（一般为16）
        writeShort(1)         // 格式种类（值为1时，表示数据为线性PCM编码）
        writeShort(channelCount)    // 通道数量，单声道为1，双声道为2
        writeInt(sampleRate)        // 采样频率
        writeInt(bytesPerSec)       // 波形数据传输速率（每秒平均字节数）
        writeShort(bytesPerFrame)   // 每帧音频的大小
        writeShort(bitDepth)        // PCM位宽
        writeString("data")     // 数据标志符（data）
        writeInt(dataTotalLength)   // data总数据长度
    }

    fun writeData(data: ByteArray, offset: Int, dataLength: Int) {
        raf.write(data, offset, dataLength)
        dataTotalLength += dataLength
    }

    fun close() {
        // 数据写完了，长度也知道了，根据长度重写文件头。
        // 按道理只需要重写关于长度的那个个数据即可，但是因为文件头很小，写入很快，就全部重写吧！
        raf.seek(0)
        writeHeader(dataTotalLength)
        raf.close()
    }

    /** 保存4个字符 */
    private fun writeString(str: String) {
        val strBytes = str.toByteArray()
        raf.write(strBytes[0].toInt())
        raf.write(strBytes[1].toInt())
        raf.write(strBytes[2].toInt())
        raf.write(strBytes[3].toInt())
    }

    /** 写入一个Int（以小端方式写入） */
    private fun writeInt(value: Int) {
        // raf.writeInt(value) 这是以大端方式写入的
        raf.writeByte(value ushr 0 and 0xFF)
        raf.writeByte(value ushr 8 and 0xFF)
        raf.writeByte(value ushr 16 and 0xFF)
        raf.writeByte(value ushr 24 and 0xFF)
    }

    /** 写入一个Short（以小端方式写入） */
    private fun writeShort(value: Int) {
        // raf.writeShort(value) 这是以大端方式写入的
        raf.write(value ushr 0 and 0xFF)
        raf.write(value ushr 8 and 0xFF)
    }

}